package com.example.behaviour.customization.observer.multicaster;

import com.example.behaviour.customization.observer.event.AppEvent;
import com.example.behaviour.customization.observer.listener.AppListener;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 抽象事件广播器
 * 将共性代码抽取到抽象
 */
public abstract class AbstractAppEventMulticaster implements AppEventMulticaster {

    private final ListenerHelper defaultHelper = new ListenerHelper();

    private final Map<ListenerCacheKey,ListenerHelper> helperCache = new ConcurrentHashMap<>(64);

    @Override
    public void addListener(AppListener<?> listener) {
        defaultHelper.allAppListeners.add(listener);
    }

    // 内部增强类
    // 1.返回全部监听器(自定义返回类型向外暴露)
    private class ListenerHelper{
        private final Set<AppListener<?>> allAppListeners = new LinkedHashSet<>();

        // 返回全部监听器(自定义返回类型向外暴露)
        public Collection<AppListener<? extends AppEvent>> getAppListeners(){
            List<AppListener<? extends AppEvent>> appListenerList = new ArrayList<>(allAppListeners.size());
            appListenerList.addAll(allAppListeners);
            return appListenerList;
        }
    }

    protected Collection<AppListener<?>> getAppListeners(AppEvent event) {
        Object source = event.getSource();
        Class sourceType = source == null ? null : source.getClass();
        Class<? extends AppEvent> eventType = event.getClass();
        ListenerCacheKey cacheKey = new ListenerCacheKey(sourceType, eventType);
        ListenerHelper helper = helperCache.get(cacheKey);
        if (helper != null){
            return helper.getAppListeners();
        }else {
            helper = new ListenerHelper();
            Collection<AppListener<?>> allAppListener  = getAppListeners(sourceType, eventType, helper);
            helperCache.put(cacheKey, helper);
            return allAppListener;
        }
    }

    // 缓存key对象
    private class ListenerCacheKey{
        private Class sourceType;
        private Class eventType;

        public ListenerCacheKey() {
        }

        public ListenerCacheKey(Class sourceType, Class eventType) {
            this.sourceType = sourceType;
            this.eventType = eventType;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            ListenerCacheKey that = (ListenerCacheKey) o;
            return Objects.equals(sourceType, that.sourceType) && Objects.equals(eventType, that.eventType);
        }

        @Override
        public int hashCode() {
            return Objects.hash(sourceType, eventType);
        }

        @Override
        public String toString() {
            return "ListenerCacheKey{" +
                    "sourceType=" + sourceType +
                    ", eventType=" + eventType +
                    '}';
        }
    }

    /**
     * 根据 eventType sourceType 从 defaultHelper中找到对应的listener集合，填充给helper并且返回
     * @param eventType
     * @param sourceType
     * @param helper
     * @return
     */
    protected List<AppListener<? extends AppEvent>> getAppListeners(Class sourceType, Class<? extends AppEvent> eventType, ListenerHelper helper){
        Collection<AppListener<? extends AppEvent>> appListeners = defaultHelper.getAppListeners();
        List<AppListener<?>> returns = new ArrayList<>();
        for (AppListener<? extends AppEvent> listener : appListeners) {
            if (supportEvent(listener, eventType, sourceType)){
                if (helper!=null) {
                    helper.allAppListeners.add(listener);
                    returns.add(listener);
                }
            }
        }
        return returns;
    }

    private boolean supportEvent(AppListener<?> listener, Class eventType, Class sourceType) {
        return listener.supportEventType(eventType) && listener.supportSourceType(sourceType);
    }

}
